/*
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! CHECKER             Ecma builtins inlining. Speculations should be the following: (DOUBLE + Instruction) --deopt--> (DOUBLE/INT + Instruction).
//! RUN                 options: "--compiler-regex=_GLOBAL::profiling_abs", entry: "_GLOBAL::func_main_0"
//! METHOD              "profiling_abs"
//! EVENT               /Compilation,.*profiling_abs.*COMPILED/
//! PASS_AFTER          "InlineIntrinsics"
//! INST                "HclassCheck"
//! INST_NEXT           "AnyTypeCheck ECMASCRIPT_DOUBLE_TYPE"
//! INST_NEXT           "CastAnyTypeValue ECMASCRIPT_DOUBLE_TYPE"
//! INST_NEXT_NOT       "Cast "
//! INST_NEXT           "Abs"
//! EVENT_NEXT          /DeoptimizationReason,.*,DOUBLE_WITH_INT/
//! EVENT_NEXT          /Compilation,.*profiling_abs.*COMPILED/
//! PASS_AFTER_NEXT     "InlineIntrinsics"
//! INST                "HclassCheck"
//! INST_NEXT           "AnyTypeCheck ECMASCRIPT_DOUBLE_TYPE"
//! INST_NEXT           "CastAnyTypeValue ECMASCRIPT_DOUBLE_TYPE"
//! INST_NEXT_NOT       "Cast "
//! INST_NEXT           "Abs"
//! EVENT_NEXT_NOT      /Deoptimization/
//! EVENT_NEXT_NOT      /Compilation/

function profiling_abs(arg)
{
    let saved_arg = arg;
    // Increment is necessary to profile the type:
    let res = Math.abs(arg++);
    arg = saved_arg;
    return res;
}

function check(arg)
{
    let lhs = Math.abs(arg);
    let rhs = profiling_abs(arg);
    if (lhs != rhs) {
        throw "Wrong result " + lhs + " " + rhs;
    }
    RuntimeTesting.OptimizeFunctionOnNextCall(profiling_abs);
    lhs = Math.abs(arg);
    rhs = profiling_abs(arg);
    if (lhs != rhs) {
        throw "Wrong result " + lhs + " " + rhs;
    }

};

RuntimeTesting.PrepareFunctionForOptimization(profiling_abs);

// Profile as double:
check(3.1);
// Deopt, profile as double with int
check(3);
// No deoptimization
check(3);
check(3.1);
check(3);
check(3.1);
